--- title: "07-Object 类与 equals-hashCode" aliases: - "Object 类与 equals-hashCode" created: 2025-12-25 --- # Object 类与 equals/hashCode ## **一、Object 类概述** ### **1.1 Object 类的地位** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#fdfdfe" }, "flowchart": { "curve": "basis", "htmlLabels": true } }}%% flowchart TB %% 样式定义 classDef root fill:#e8f5e9,stroke:#4caf50,stroke-width:2.5px,color:#1b5e20; classDef mid fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef leaf fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; classDef info fill:#fff3e0,stroke:#ff9800,stroke-dasharray: 5 5,color:#e65100; %% 核心继承结构 subgraph Hierarchy ["Java 类继承体系"] direction TB Root["Object
(所有类的根类)"] subgraph Level1 ["第一层继承"] StringNode["String"] NumberNode["Number"] CustomClass["你的自定义类"] end subgraph Level2 ["第二层继承 (以 Number 为例)"] IntegerNode["Integer"] DoubleNode["Double"] LongNode["Long"] end %% 建立连接 Root ==> StringNode Root ==> NumberNode Root ==> CustomClass NumberNode --> IntegerNode NumberNode --> DoubleNode NumberNode --> LongNode end %% 特点说明 subgraph Features ["Object 类核心特点"] F1["所有类直接或间接继承 Object"] F2["省略 extends 时编译器自动补全"] F3["所有对象均拥有 Object 的基础方法"] end %% 节点应用样式 class Root root; class StringNode,NumberNode,CustomClass mid; class IntegerNode,DoubleNode,LongNode leaf; class F1,F2,F3 info; %% 布局辅助 Hierarchy ~~~ Features ``` ```java // 这两种写法等价 public class Person { } public class Person extends Object { } ``` ### **1.2 Object 类的 11 个方法** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart LR %% 核心根节点 Root(["Java Object 类方法全景图"]) %% 分支 1:比较与标识 subgraph Group1 ["1. 对象比较与标识"] direction TB M1_1["equals(Object obj)
对象相等性比较"] M1_2["hashCode()
返回对象哈希码"] M1_3["toString()
返回对象字符串表示"] end %% 分支 2:对象克隆 subgraph Group2 ["2. 对象克隆"] M2_1["clone()
创建并返回对象副本"] end %% 分支 3:类型信息 subgraph Group3 ["3. 类型信息"] M3_1["getClass()
获取运行时 Class 对象"] end %% 分支 4:线程同步 subgraph Group4 ["4. 线程同步 (Monitor)"] direction TB M4_1["wait() / wait(ms) / wait(ms, ns)
线程进入等待状态"] M4_2["notify()
唤醒单个等待线程"] M4_3["notifyAll()
唤醒所有等待线程"] end %% 分支 5:垃圾回收 subgraph Group5 ["5. 垃圾回收"] M5_1["finalize()
对象销毁前回调 (已废弃)"] end %% 连接关系 Root ==> Group1 Root ==> Group2 Root ==> Group3 Root ==> Group4 Root ==> Group5 %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; classDef deprecated fill:#ffebee,stroke:#f44336,stroke-width:1px,color:#b71c1c; %% 应用样式 class Root main; class M1_1,M1_2,M1_3 main; class M2_1 storage; class M3_1 term; class M4_1,M4_2,M4_3 decision; class M5_1 deprecated; ``` ### **1.3 方法详情表** | **方法** | **修饰符** | **返回类型** | **说明** | | --- | --- | --- | --- | | `getClass()` | public final native | Class | 获取运行时类对象 | | `hashCode()` | public native | int | 返回对象哈希码 | | `equals(Object obj)` | public | boolean | 判断对象是否相等 | | `clone()` | protected native | Object | 创建并返回对象副本 | | `toString()` | public | String | 返回对象字符串表示 | | `notify()` | public final native | void | 唤醒一个等待线程 | | `notifyAll()` | public final native | void | 唤醒所有等待线程 | | `wait()` | public final | void | 使当前线程等待 | | `wait(long)` | public final native | void | 限时等待 | | `wait(long, int)` | public final | void | 精确限时等待 | | `finalize()` | protected | void | GC 回收前调用(已废弃) | > ***native**:表示方法由 C/C++ 实现,不是 Java 代码* > ***final**:表示方法不能被重写* ### **1.4 核心方法源码** ```java /** * Object 类核心方法源码(简化版) */ public class Object { // ===== 1. getClass() ===== // 返回运行时类型,不能重写 public final native Class getClass(); // ===== 2. hashCode() ===== // 默认返回对象内存地址转换的整数 public native int hashCode(); // ===== 3. equals() ===== // 默认比较引用地址 public boolean equals(Object obj) { return (this == obj); } // ===== 4. clone() ===== // 创建对象副本,需要实现 Cloneable 接口 protected native Object clone() throws CloneNotSupportedException; // ===== 5. toString() ===== // 默认返回:类名@十六进制哈希码 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } // ===== 6-10. 线程相关方法 ===== public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException { ... } public final void wait() throws InterruptedException { ... } // ===== 11. finalize() ===== // 已废弃,Java 9 标记 @Deprecated @Deprecated(since="9") protected void finalize() throws Throwable { } } ``` ## **二、== 运算符详解** ### **2.1 == 的行为规则** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "fontFamily": "arial" }, "flowchart": { "curve": "basis", "htmlLabels": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:2px,color:#0d47a1; classDef typeNode fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef logicNode fill:#f1f8e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef codeNode fill:#f5f5f5,stroke:#9e9e9e,stroke-width:1px,color:#333,font-family:monospace; %% 核心结构 Start(["== 运算符的行为"]) --> Root{"比较对象 a == b"} %% 分支1:基本类型 Root --> Primitive["基本数据类型
(Primitive Types)"] Primitive --> PrimLogic["比较【值】是否相等"] subgraph PrimExample ["基本类型示例"] direction TB PCode["int a = 5;
int b = 5;"] PRes{"a == b → true"} PCode --- PRes end %% 分支2:引用类型 Root --> Reference["引用数据类型
(Reference Types)"] Reference --> RefLogic["比较【内存地址】
是否指向同一对象"] subgraph RefExample ["引用类型示例"] direction TB RCode["Object o1 = new Object();
Object o2 = new Object();"] RRes1["o1 == o2 → false"] RRes2["o1 == o1 → true"] RCode --- RRes1 RCode --- RRes2 end %% 连接示例 PrimLogic ==> PrimExample RefLogic ==> RefExample %% 类应用 class Start main; class Root typeNode; class Primitive,Reference typeNode; class PrimLogic,RefLogic logicNode; class PCode,RCode,PRes,RRes1,RRes2 codeNode; ``` ### **2.2 基本类型的 == 比较** ```java public class PrimitiveEqualsDemo { public static void main(String[] args) { // ===== 整数类型 ===== int a = 100; int b = 100; System.out.println("int: " + (a == b)); // true long c = 100L; System.out.println("int == long: " + (a == c)); // true(自动类型提升) // ===== 浮点类型 ===== double d1 = 0.1 + 0.2; double d2 = 0.3; System.out.println("double: " + (d1 == d2)); // false!(精度问题) System.out.println("d1 = " + d1); // 0.30000000000000004 // ===== 字符类型 ===== char ch1 = 'A'; char ch2 = 65; System.out.println("char: " + (ch1 == ch2)); // true('A'的ASCII码是65) // ===== 布尔类型 ===== boolean bool1 = true; boolean bool2 = true; System.out.println("boolean: " + (bool1 == bool2)); // true } } ``` ### **2.3 引用类型的 == 比较** ```java public class ReferenceEqualsDemo { public static void main(String[] args) { // ===== 普通对象 ===== Person p1 = new Person("张三", 20); Person p2 = new Person("张三", 20); Person p3 = p1; System.out.println("p1 == p2: " + (p1 == p2)); // false(不同对象) System.out.println("p1 == p3: " + (p1 == p3)); // true(同一对象) // ===== String 特殊情况 ===== String s1 = "Hello"; String s2 = "Hello"; String s3 = new String("Hello"); System.out.println("s1 == s2: " + (s1 == s2)); // true(字符串常量池) System.out.println("s1 == s3: " + (s1 == s3)); // false(s3是新对象) // ===== 包装类特殊情况 ===== Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println("i1 == i2: " + (i1 == i2)); // true(缓存池 -128~127) System.out.println("i3 == i4: " + (i3 == i4)); // false(超出缓存范围) } } ``` ### **2.4 == 比较内存图解** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB subgraph Primitive ["基本类型:比较栈中的值"] direction LR subgraph Stack1 ["栈内存"] A1["a = 100"] B1["b = 100"] end Compare1{"100 == 100"} Result1(["true"]) A1 --> Compare1 B1 --> Compare1 Compare1 ==> Result1 end subgraph Reference ["引用类型:比较栈中的地址"] direction TB subgraph MemoryLayout ["内存结构"] direction LR subgraph Stack2 ["栈内存 (存储地址)"] P1["p1 = 0x100"] P2["p2 = 0x200"] P3["p3 = 0x100"] end subgraph Heap ["堆内存 (实际对象)"] ObjA[("Person 对象 A
(0x100)")] ObjB[("Person 对象 B
(0x200)")] end P1 ==> ObjA P3 ==> ObjA P2 ==> ObjB end subgraph Logic ["逻辑判断"] direction LR Cond1{"p1 == p2
(0x100 == 0x200)"} -.-> Res1(["false"]) Cond2{"p1 == p3
(0x100 == 0x100)"} ==> Res2(["true"]) end end %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; class A1,B1,P1,P2,P3 main; class Compare1,Cond1,Cond2 decision; class Result1,Res1,Res2 term; class ObjA,ObjB storage; ``` ## **三、equals() 方法详解** ### **3.1 Object.equals() 默认实现** ```java // Object 类中的默认实现 public boolean equals(Object obj) { return (this == obj); // 默认就是比较引用! } ``` ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef code fill:#f5f5f5,stroke:#90a4ae,stroke-width:1px,color:#263238; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef warning fill:#ffebee,stroke:#f44336,stroke-width:1px,color:#b71c1c; classDef solution fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; subgraph DefaultBehavior ["Object.equals() 默认行为解析"] direction TB Start(["开始调用 p1.equals(p2)"]) --> Logic{"内部实现逻辑"} Logic -- "默认实现" --> RawCode["return (this == obj);"] subgraph InstanceComparison ["堆内存对象对比"] direction LR P1[("p1 (张三, 20)")] P2[("p2 (张三, 20)")] P1 -. "物理地址不同" .-> P2 end RawCode --> Compare{地址是否一致?} Compare -- "NO" --> ResultFalse(["结果: false"]) Problem["问题点
内容完全相同的对象
被判定为不相等"] ResultFalse ==> Problem end subgraph SolutionPath ["改进方案"] direction TB Overriding[["重写 equals() 方法"]] LogicChange["改为比较成员变量
(name, age)"] ResultTrue(["预期结果: true"]) Overriding --> LogicChange --> ResultTrue end Problem ==> Overriding %% 节点样式应用 class Start,ResultFalse main; class RawCode,InstanceComparison code; class Logic,Compare decision; class Problem warning; class Overriding,ResultTrue solution; ``` ### **3.2 String.equals() 源码分析** ```java /** * String 类重写的 equals 方法(JDK 8) */ public boolean equals(Object anObject) { // 1. 首先检查是否是同一个对象(快速路径) if (this == anObject) { return true; } // 2. 检查类型是否是 String if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; // 3. 比较长度 if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; // 4. 逐字符比较 while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } ``` **流程**图: ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TD %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef error fill:#ffebee,stroke:#f44336,stroke-width:1.5px,color:#b71c1c; %% 节点定义 Start(["开始比较 String.equals(anObject)"]) CheckRef{"this == anObject
(引用地址相同?)"} CheckType{"anObject instanceof String
(是否为字符串?)"} CheckLength{"length 相同?"} CheckChars{"逐字符循环比较
全部字符相同?"} RetTrue(["return true"]) RetFalse(["return false"]) %% 流程连接 Start --> CheckRef CheckRef == "是 (YES)" ==> RetTrue CheckRef -- "否 (NO)" --> CheckType CheckType -. "否 (NO)" .-> RetFalse CheckType == "是 (YES)" ==> CheckLength CheckLength -. "否 (NO)" .-> RetFalse CheckLength == "是 (YES)" ==> CheckChars CheckChars == "是 (YES)" ==> RetTrue CheckChars -. "否 (NO)" .-> RetFalse %% 应用样式 class Start,CheckLength,CheckChars main; class CheckRef,CheckType decision; class RetTrue term; class RetFalse error; %% 子图修饰 subgraph Logic ["String.equals() 内部逻辑路径"] CheckRef CheckType CheckLength CheckChars end ``` ### **3.3 正确重写 equals() 方法** ```java public class Person { private String name; private int age; private Address address; // 构造方法、Getter/Setter 省略 /** * 重写 equals 方法 */ @Override public boolean equals(Object obj) { // 1. 检查是否是同一个对象的引用 if (this == obj) { return true; } // 2. 检查 obj 是否为 null if (obj == null) { return false; } // 3. 检查是否是同一个类型 // 方式一:getClass()(严格类型匹配) if (getClass() != obj.getClass()) { return false; } // 方式二:instanceof(允许子类相等,但可能违反对称性) // if (!(obj instanceof Person)) { // return false; // } // 4. 强制类型转换 Person other = (Person) obj; // 5. 比较关键属性 // 基本类型:用 == if (this.age != other.age) { return false; } // 引用类型:用 equals(注意 null 处理) if (this.name == null) { if (other.name != null) { return false; } } else if (!this.name.equals(other.name)) { return false; } // 使用 Objects.equals() 更简洁 // return age == other.age && // Objects.equals(name, other.name) && // Objects.equals(address, other.address); return true; } } ``` ### **3.4 使用 Objects.equals() 简化** ```java import java.util.Objects; public class Person { private String name; private int age; private Address address; @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person person = (Person) obj; // 使用 Objects.equals() 自动处理 null return age == person.age && Objects.equals(name, person.name) && Objects.equals(address, person.address); } } ``` **Objects.equals()** 源码: ```java public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } ``` ### **3.5 equals() 的五个规范** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef highlight fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef ruleBox fill:#ffffff,stroke:#cfd8dc,stroke-width:1px,color:#37474f; Title(["Java equals() 方法遵循的五大规范"]) subgraph CoreRules ["核心等价关系规范"] direction TB Rule1["1. 自反性 (Reflexive)"] Desc1["x.equals(x) 恒为 true
(对象必须等于自身)"] Rule2["2. 对称性 (Symmetric)"] Desc2["若 x.equals(y) 为 true
则 y.equals(x) 必为 true"] Rule3["3. 传递性 (Transitive)"] Desc3["若 x.equals(y) 且 y.equals(z) 为 true
则 x.equals(z) 必为 true"] Rule1 --- Desc1 Rule2 --- Desc2 Rule3 --- Desc3 end subgraph StabilityRules ["稳定性与健壮性规范"] direction TB Rule4["4. 一致性 (Consistent)"] Desc4["只要对象状态未变
多次调用结果必须一致"] Rule5["5. 非空性 (Non-nullity)"] Desc5["x.equals(null) 必须返回 false
(任何对象不等于 null)"] Rule4 --- Desc4 Rule5 --- Desc5 end %% 连接标题与子图 Title ==> CoreRules Title ==> StabilityRules %% 应用样式 class Title highlight class Rule1,Rule2,Rule3,Rule4,Rule5 main class Desc1,Desc2,Desc3,Desc4,Desc5 ruleBox ``` ## **四、== 与 equals() 对比** ### **4.1 核心区别** | **对比项** | **==** | **equals()** | | --- | --- | --- | | **本质** | 运算符 | 方法 | | **基本类型** | 比较值 | 不适用(基本类型没有方法) | | **引用类型** | 比较地址 | 默认比较地址,可重写比较内容 | | **能否重写** | 不能 | 可以 | | **null 处理** | 可以用于 null | null.equals() 会 NPE | --- ### **4.2 对比图解** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; %% 场景初始化 Start(["场景:比较两个 Person 对象
p1 = new Person('张三', 20)
p2 = new Person('张三', 20)"]) subgraph DoubleEqual ["== 运算符比较"] direction TB Op1["p1 == p2"] Comp1["比较堆内存引用地址
(0x100 == 0x200 ?)"] Res1(["false
(不是同一个对象)"]) Op1 --> Comp1 Comp1 --> Res1 end subgraph EqualsMethod ["equals() 方法比较"] direction TB Op2["p1.equals(p2)"] CheckOverride{"是否重写了
equals 方法?"} NoOverride["未重写 (调用 Object 类)"] HasOverride["已重写 (业务逻辑)"] Comp2["比较引用地址
(逻辑同 ==)"] Comp3["比较对象内容
(name.equals && age ==)"] Res2(["false"]) Res3(["true
(内容逻辑相同)"]) Op2 --> CheckOverride CheckOverride -- "No" --> NoOverride CheckOverride -- "Yes" --> HasOverride NoOverride --> Comp2 HasOverride --> Comp3 Comp2 --> Res2 Comp3 ==> Res3 end %% 顶层连接 Start ~~~ DoubleEqual Start ~~~ EqualsMethod %% 应用样式 class Start storage; class Op1,Op2 main; class CheckOverride decision; class Res1,Res2,Res3 term; ``` ### **4.3 常见陷阱与最佳实践** ```java public class EqualsTrapsDemo { public static void main(String[] args) { // ===== 陷阱 1:用 == 比较字符串内容 ===== String input = new String("admin"); // ❌ 错误写法 if (input == "admin") { System.out.println("永远不会执行"); } // ✅ 正确写法 if (input.equals("admin")) { System.out.println("正确判断"); } // ✅ 更好的写法:常量在前,避免 NPE if ("admin".equals(input)) { System.out.println("避免空指针"); } // ===== 陷阱 2:用 == 比较包装类 ===== Integer a = 128; Integer b = 128; // ❌ 可能出错(超出缓存范围) if (a == b) { System.out.println("可能不会执行"); } // ✅ 正确写法 if (a.equals(b)) { System.out.println("正确判断"); } // ✅ 或者拆箱比较 if (a.intValue() == b.intValue()) { System.out.println("正确判断"); } // ===== 陷阱 3:null 调用 equals ===== String str = null; // ❌ 会抛出 NullPointerException // if (str.equals("test")) { } // ✅ 使用 Objects.equals() if (Objects.equals(str, "test")) { System.out.println("安全比较"); } } } ``` ## **五、hashCode() 方法详解** ### **5.1 hashCode() 的作用** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true } }}%% flowchart TB %% 核心概念定义 Start(["hashCode() 的作用"]) Definition["返回对象的哈希码 (int)
主要用于哈希表快速定位"] subgraph Comparison ["查找效率对比"] direction LR subgraph Traditional ["没有 hashCode"] T1["逐个比较 equals()"] T2["时间复杂度: O(n)"] T1 --> T2 end subgraph Optimized ["有了 hashCode"] O1["1. 计算 hashCode 定位桶位置"] O2["2. 桶内进行 equals() 比较"] O3["时间复杂度: 接近 O(1)"] O1 ==> O2 ==> O3 end end %% 连接逻辑 Start --> Definition Definition --> Comparison %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; %% 应用样式 class Start,Definition main; class O1,O2,O3 term; class T1,T2 decision; ``` ### **5.2 HashMap/HashSet 工作原理** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TD %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; %% 流程节点 Start(["开始: set.add(obj)"]) --> CalcHash["Step 1: 计算 hashCode
int hash = obj.hashCode()"] CalcHash --> CalcIndex["Step 2: 计算桶位置
int index = hash % 数组长度"] subgraph BucketProcess ["哈希表寻址与冲突检查"] CalcIndex --> CheckEmpty{"Step 3: 检查桶是否为空"} CheckEmpty -- "是 (null)" --> DirectInsert["直接插入到该索引位置"] CheckEmpty -- "否 (已有数据)" --> TraverseList["Step 4: 遍历链表/红黑树
调用 equals() 逐一比较"] TraverseList --> EqualCheck{"是否存在相同元素?"} EqualCheck -- "找到相同
(equals == true)" --> Discard["放弃添加 (保证唯一性)"] EqualCheck -- "未找到相同
(equals == false)" --> ListInsert["添加到链表末尾或红黑树"] end %% 结束节点 DirectInsert ==> Success(["添加成功"]) ListInsert ==> Success Discard -.-> Fail(["添加失败 (已存在)"]) %% 指派样式 class Start,CalcHash,CalcIndex,TraverseList main; class CheckEmpty,EqualCheck decision; class Success,ListInsert,DirectInsert term; class Discard,Fail storage; ``` ### **5.3 哈希表结构图** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB subgraph Container ["HashMap 内部数据结构 (Java 8+)"] direction TB subgraph ArrayLayer ["Node<K,V>[] table (数组/桶)"] direction LR B0["Index 0"] B1["Index 1"] B2["Index 2"] B3["Index 3"] B4["Index 4"] B5["Index 5"] B6["Index 6"] B7["Index 7"] end %% 链表结构 1 B0 --> NodeA["Node A:1"] NodeA --> NodeB["Node B:2"] %% 空位 B1 --> Null1(["null"]) %% 链表结构 2 B3 --> NodeC["Node C:3"] NodeC --> NodeD["Node D:4"] %% 链表转红黑树示意 B5 --> NodeE["Node E:5"] NodeE --> NodeF["Node F:6"] NodeF --> NodeG["Node G:7"] NodeG -.-> Tree{{"红黑树节点
TreeNode"}} subgraph Logic ["转换逻辑说明"] Rule["当链表长度 > 8 且数组长度 > 64 时"] end end %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef bucket fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; classDef node fill:#ffffff,stroke:#546e7a,stroke-width:1px; classDef special fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef tip fill:#e8f5e9,stroke:#4caf50,stroke-dasharray: 5 5; class B0,B1,B2,B3,B4,B5,B6,B7 bucket; class NodeA,NodeB,NodeC,NodeD,NodeE,NodeF,NodeG node; class Tree special; class Rule tip; class Container main; ``` ### **5.4 Object.hashCode() 默认实现** ``` // Object 类中的默认实现(native 方法) public native int hashCode(); ``` ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef code fill:#f5f5f5,stroke:#90a4ae,stroke-width:1px,color:#263238,font-family:monospace; classDef warning fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef highlight fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; subgraph Header ["Object.hashCode() 默认行为解析"] direction TB Title["默认实现:基于对象内部标识(Native)计算
通常与内存地址相关,但由 JVM 具体实现决定"] end subgraph Characteristics ["核心特点"] direction LR C1["一致性
同一对象生命周期内
hashCode 保持不变"] C2["区分性
不同对象通常拥有
不同的 hashCode"] C3["冲突性
不同对象可能产生
相同 hash (概率极低)"] end subgraph Example ["代码实例与内存表现"] direction TB CodeBlock["Person p1 = new Person('张三', 20);
Person p2 = new Person('张三', 20);"] subgraph Memory ["JVM 堆内存状态"] direction LR Obj1["对象 p1
(内容: 张三, 20)
Hash: 123"] Obj2["对象 p2
(内容: 张三, 20)
Hash: 456"] end end subgraph Consequence ["默认行为的影响"] Impact{"内容相同
但 Hash 不同"} Result["HashSet / HashMap 失效
p1 与 p2 会被视为两个独立元素
存入集合,导致逻辑重复"] end %% 逻辑连接 Title --> Characteristics Characteristics --> CodeBlock CodeBlock --> Obj1 CodeBlock --> Obj2 Obj1 -.-> Impact Obj2 -.-> Impact Impact ==> Result %% 类应用 class Title,C1,C2,C3 main; class CodeBlock code; class Obj1,Obj2 highlight; class Impact,Result warning; ``` ## **六、equals 和 hashCode 的关系** ### **6.1 核心规范** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef must fill:#e8f5e9,stroke:#4caf50,stroke-width:2px,color:#1b5e20; classDef optional fill:#f5f5f5,stroke:#9e9e9e,stroke-dasharray: 5 5,color:#616161; subgraph Contract ["Java equals & hashCode 契约关系"] direction TB %% 规则 1 路径 R1_Start{"a.equals(b) == true"} R1_Result(["必须相等 (Consistency)"]) R1_Start == "强制要求" ==> R1_Result %% 规则 2 路径 R2_Start{"a.hashCode() == b.hashCode()"} R2_True["a.equals(b) == true"] R2_False["a.equals(b) == false"] R2_Start -. "可能" .-> R2_True R2_Start -. "也可能 (哈希冲突)" .-> R2_False %% 规则 3 路径 R3_Start{"a.equals(b) == false"} R3_Diff(["推荐:提高散列性能"]) R3_Same(["允许:但产生冲突"]) R3_Start ==> R3_Diff R3_Start -. "允许但性能下降" .-> R3_Same end %% 应用样式 class R1_Start,R2_Start,R3_Start decision class R1_Result,R3_Diff must class R2_True main class R2_False,R3_Same optional %% 补充说明 note1["规则 1:
如果两个对象相等,
它们的 HashCode 必须相同"] note2["规则 2:
HashCode 相同不代表对象相等
(Bucket 碰撞)"] note1 --- R1_Start note2 --- R2_Start ``` ### **6.2 图解规则** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef success fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef error fill:#ffebee,stroke:#f44336,stroke-width:1.5px,color:#b71c1c; %% 核心逻辑 Start(["开始判断对象关系"]) --> HashCheck{"hashCode 是否相等?"} %% hashCode 相等分支 subgraph HashEqualGroup ["hashCode 相等 (存在潜在关联)"] HashCheck -- "相等" --> EqualsCheck{"equals 是否相等?"} EqualsCheck -- "相等" --> Case1["✅ 合法:对象完全相同"] EqualsCheck -- "不等" --> Case2["✅ 合法:哈希冲突 (Collision)"] end %% hashCode 不相等分支 subgraph HashNotEqualGroup ["hashCode 不相等"] HashCheck -- "不相等" --> Case3["✅ 合法:equals 必定不等"] end %% 违规约束 Constraint{"违反原则的情况"} -.-> Illegal["❌ 非法:equals 相等但 hashCode 不等"] %% 节点样式应用 class Start main; class HashCheck,EqualsCheck decision; class Case1,Case2,Case3 success; class Illegal error; %% 补充说明 note1["注:Java 规范要求若 equals 相等,则 hashCode 必须相等"] Case1 ~~~ note1 style note1 fill:#fafafa,stroke:#ccc,stroke-dasharray: 5 5,color:#666; ``` ### **6.3 为什么重写 equals 必须重写 hashCode?** ```java /** * 只重写 equals,不重写 hashCode 的问题演示 */ public class BrokenPerson { private String name; private int age; public BrokenPerson(String name, int age) { this.name = name; this.age = age; } // 只重写了 equals @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; BrokenPerson other = (BrokenPerson) obj; return age == other.age && Objects.equals(name, other.name); } // ❌ 没有重写 hashCode! } public class BrokenDemo { public static void main(String[] args) { BrokenPerson p1 = new BrokenPerson("张三", 20); BrokenPerson p2 = new BrokenPerson("张三", 20); // equals 返回 true System.out.println("p1.equals(p2): " + p1.equals(p2)); // true // 但 hashCode 不同! System.out.println("p1.hashCode(): " + p1.hashCode()); // 例如:366712642 System.out.println("p2.hashCode(): " + p2.hashCode()); // 例如:1829164700 // ===== 在 HashSet 中出问题 ===== Set set = new HashSet<>(); set.add(p1); set.add(p2); System.out.println("set.size(): " + set.size()); // 2 ❌ 应该是 1 // ===== 查找失败 ===== BrokenPerson p3 = new BrokenPerson("张三", 20); System.out.println("set.contains(p3): " + set.contains(p3)); // false ❌ } } ``` 问题分析: ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB subgraph Analysis ["问题根源分析:未重写 hashCode 导致重复"] direction TB subgraph Objects ["对象状态 (p1.equals(p2) == true)"] P1["对象 p1
hashCode: 366712642"] P2["对象 p2
hashCode: 1829164700"] end subgraph Process ["HashSet.add() 内部逻辑"] direction LR Calc1["计算 p1 桶位
366712642 % 16 = 2"] Calc2["计算 p2 桶位
1829164700 % 16 = 12"] end subgraph Storage ["HashMap 桶数组 (Buckets)"] direction LR B2[("桶 [2]")] B12[("桶 [12]")] Other["其他桶..."] end subgraph Result ["最终结果"] Fail["逻辑冲突
p1 与 p2 位于不同桶
无法触发 equals() 检查"] end end %% 连线关系 P1 ==> Calc1 P2 ==> Calc2 Calc1 ==> B2 Calc2 ==> B12 B2 -.-> Result B12 -.-> Result %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; classDef alert fill:#ffebee,stroke:#f44336,stroke-width:2px,color:#b71c1c; class P1,P2,Calc1,Calc2 main; class B2,B12,Other storage; class Result,Fail alert; ``` ### **6.4 正确实现** ```java import java.util.Objects; public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // ✅ 正确重写 equals @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person person = (Person) obj; return age == person.age && Objects.equals(name, person.name); } // ✅ 正确重写 hashCode(使用相同的属性) @Override public int hashCode() { return Objects.hash(name, age); } } ``` **验**证: ```java public class CorrectDemo { public static void main(String[] args) { Person p1 = new Person("张三", 20); Person p2 = new Person("张三", 20); System.out.println("p1.equals(p2): " + p1.equals(p2)); // true System.out.println("p1.hashCode(): " + p1.hashCode()); // 相同 System.out.println("p2.hashCode(): " + p2.hashCode()); // 相同 Set set = new HashSet<>(); set.add(p1); set.add(p2); System.out.println("set.size(): " + set.size()); // 1 ✅ System.out.println("set.contains(new Person(\"张三\", 20)): " + set.contains(new Person("张三", 20))); // true ✅ } } ``` ## **七、Objects.hash() 源码分析** ### **7.1 源码** ```java /** * java.util.Objects 类 */ public final class Objects { public static int hash(Object... values) { return Arrays.hashCode(values); } } /** * java.util.Arrays 类 */ public class Arrays { public static int hashCode(Object[] a) { if (a == null) return 0; int result = 1; for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; } } ``` ### **7.2 为什么使用 31 作为乘数?** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 核心公式展示 Formula(["hash = 31 * hash + element.hashCode()"]) %% 三大核心理由 subgraph Reasons ["为什么选择 31?"] direction TB subgraph Math ["1. 数学特性 (奇素数)"] direction TB Prime["素数 (Prime)
减少哈希冲突的可能性"] Odd["奇数 (Odd)
避免乘法溢出时低位丢失信息"] end subgraph Perf ["2. 性能优化 (JVM)"] direction TB Shift["位运算优化
31 * i == (i << 5) - i"] Fast["执行效率高
移位和减法比传统乘法更快"] end subgraph Practice ["3. 工业实践 (经验值)"] direction TB Uniform["分布均匀
在大数据测试中冲突率极低"] Standard["标准实现
JDK String 等类广泛采用"] end end %% 连接关系 Formula ==> Reasons Math ~~~ Perf Perf ~~~ Practice %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef highlight fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef subbox fill:#f9f9f9,stroke:#cfd8dc,stroke-dasharray: 5 5; class Formula highlight; class Prime,Odd,Shift,Fast,Uniform,Standard main; class Math,Perf,Practice subbox; ``` ### **7.3 手动实现 hashCode** ```java public class Person { private String name; private int age; private Address address; // 方式一:使用 Objects.hash()(推荐) @Override public int hashCode() { return Objects.hash(name, age, address); } // 方式二:手动实现 @Override public int hashCode() { int result = 17; // 非零初始值 result = 31 * result + (name == null ? 0 : name.hashCode()); result = 31 * result + age; result = 31 * result + (address == null ? 0 : address.hashCode()); return result; } // 方式三:Java 7+ 使用 Objects 工具类 @Override public int hashCode() { return Objects.hash(name, age, address); } } ``` ## **八、最佳实践** ### **8.1 使用 IDE 自动生成** ```java /** * IDEA 自动生成的 equals 和 hashCode * 快捷键:Alt + Insert → equals() and hashCode() */ public class Person { private String name; private int age; private Address address; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name) && Objects.equals(address, person.address); } @Override public int hashCode() { return Objects.hash(name, age, address); } } ``` ### **8.2 使用 Lombok 注解** ```java import lombok.EqualsAndHashCode; import lombok.Data; // 方式一:只生成 equals 和 hashCode @EqualsAndHashCode public class Person { private String name; private int age; } // 方式二:使用 @Data(包含 equals、hashCode、toString、getter、setter) @Data public class Person { private String name; private int age; } // 方式三:排除某些字段 @EqualsAndHashCode(exclude = {"id", "createTime"}) public class Person { private Long id; private String name; private int age; private LocalDateTime createTime; } // 方式四:只包含某些字段 @EqualsAndHashCode(of = {"name", "age"}) public class Person { private Long id; private String name; private int age; } ``` ### **8.3 注意事项** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB subgraph CorePrinciple ["核心原则:一致性与不变性"] P1["1. 属性同步:equals 与 hashCode 必须使用完全相同的属性集合"] P2["2. 不变性:参与计算的属性应尽量为不可变 (final)"] end subgraph Implementation ["实现细节与最佳实践"] direction LR subgraph Safety ["安全性保障"] S1{"类型检查"} S1 -- "推荐" --> S1_A["使用 getClass()
(保证对称性)"] S1 -. "慎用" .-> S1_B["使用 instanceof
(继承场景易出错)"] S2["Null 安全"] S2 --> S2_A["使用 Objects.equals()"] S2 --> S2_B["使用 Objects.hash()"] end end subgraph RiskWarning ["风险警示:违规后果"] R1[("HashSet/HashMap")] R2["修改已存入对象的属性"] R3["hashCode 发生改变"] R4["无法检索到该对象 (内存泄漏风险)"] R1 --> R2 --> R3 --> R4 end %% 逻辑连接 CorePrinciple ==> Implementation P2 -. "如果不遵守" .-> RiskWarning %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef warning fill:#ffebee,stroke:#f44336,stroke-width:1.5px,color:#b71c1c; class P1,P2,S2_A,S2_B main; class S1 decision; class S1_A,S1_B term; class R1,R2,R3,R4 warning; ``` ## **九、toString() 方法** ### **9.1 默认实现** ```java // Object 类中的默认实现 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } ``` ``` Person p = new Person("张三", 20); System.out.println(p.toString()); // 输出:com.example.Person@1b6d3586 ``` ### **9.2 重写 toString()** ```java public class Person { private String name; private int age; // 方式一:手动拼接 @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } // 方式二:使用 String.format @Override public String toString() { return String.format("Person{name='%s', age=%d}", name, age); } // 方式三:使用 StringBuilder @Override public String toString() { return new StringBuilder() .append("Person{") .append("name='").append(name).append("'") .append(", age=").append(age) .append("}") .toString(); } // 方式四:使用 StringJoiner(Java 8+) @Override public String toString() { return new StringJoiner(", ", Person.class.getSimpleName() + "[", "]") .add("name='" + name + "'") .add("age=" + age) .toString(); } } ``` ## **十、核心总结** ### **10.1 速查表** | **方法** | **默认行为** | **是否需要重写** | **重写目的** | | --- | --- | --- | --- | | `equals()` | 比较引用地址 | ✅ 通常需要 | 比较对象内容 | | `hashCode()` | 基于内存地址 | ✅ 通常需要 | 配合哈希表使用 | | `toString()` | 类名@哈希码 | ✅ 建议重写 | 输出有意义的信息 | | `clone()` | 浅拷贝 | ⚠️ 按需重写 | 实现深拷贝 | | `getClass()` | 返回 Class 对象 | ❌ 不能重写 | final 方法 | | `wait/notify` | 线程等待/唤醒 | ❌ 不能重写 | final 方法 | | `finalize()` | 空实现 | ❌ 已废弃 | 不建议使用 | --- ### **10.2 记忆口诀** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 核心标题 Title(["Java 对象比较与哈希口诀指南"]) subgraph Comparison ["== 与 equals:核心区别"] C1["基本比值,引用比址"] C2["equals 默认同 ==
重写才比内容"] C1 --- C2 end subgraph HashContract ["equals 与 hashCode:契约关系"] H1["equals 相等 ==> hashCode 必等"] H2["hashCode 相等 -.-> equals 不一定"] H3["重写一个,必须重写另一个"] H4["使用相同的属性来计算"] H1 --- H2 H2 --- H3 H3 --- H4 end subgraph BestPractice ["实践口诀:避坑与提效"] P1["比较字符串/包装类用 equals"] P2["'常量'.equals(变量)
常量放前面,空指针不来"] P3["IDE 一键生成
Lombok @Data 更简洁"] P1 --- P2 P2 --- P3 end %% 逻辑连接 Title ==> Comparison Comparison ==> HashContract HashContract ==> BestPractice %% 样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; class Title main; class C1,C2 decision; class H1,H2,H3,H4 term; class P1,P2,P3 main; ``` ### **10.3 核心要点图** ```mermaid %%{init: { "theme": "base", "themeVariables": { "primaryColor": "#e3f2fd", "primaryTextColor": "#0d47a1", "primaryBorderColor": "#2196f3", "lineColor": "#546e7a", "fontSize": "14px", "tertiaryColor": "#f5f5f5" }, "flowchart": { "curve": "basis", "htmlLabels": true, "useMaxWidth": true } }}%% flowchart TB %% 核心样式定义 classDef main fill:#e3f2fd,stroke:#2196f3,stroke-width:1.5px,color:#0d47a1; classDef decision fill:#fff3e0,stroke:#ff9800,stroke-width:1.5px,color:#e65100; classDef term fill:#e8f5e9,stroke:#4caf50,stroke-width:1.5px,color:#1b5e20; classDef storage fill:#f3e5f5,stroke:#9c27b0,stroke-width:1.5px,color:#4a148c; Root(["Java Object 核心机制总结"]) subgraph Hierarchy ["1. 根类地位"] RootNode["Object 类"] Methods["拥有 11 个核心方法"] Focus["核心重写:equals / hashCode / toString"] RootNode --> Methods Methods --> Focus end subgraph Comparison ["2. == 与 equals 区别"] Compare{"比较方式"} OpEqual["== 运算符"] MethodEqual["equals() 方法"] Compare --> OpEqual Compare --> MethodEqual OpEqual -- "基本类型" --> V1["比较具体数值"] OpEqual -- "引用类型" --> V2["比较内存地址"] MethodEqual -- "默认" --> V2 MethodEqual -- "重写后" --> V3["比较对象内容"] end subgraph HashMechanism ["3. hashCode 与哈希表"] HashRole["快速定位 (HashMap/HashSet)"] Logic{"查找逻辑"} Step1["1. 比较 hashCode"] Step2["2. 调用 equals()"] HashRole --> Logic Logic --> Step1 Step1 -- "哈希冲突" --> Step2 end subgraph Rules ["4. 重写规范 & 约束"] Must["重写 equals 必须重写 hashCode"] Property["两者必须基于相同属性计算"] subgraph Contract ["五大特性"] C1["自反性 / 对称性"] C2["传递性 / 一致性"] C3["非空性 (Not-null)"] end Must --> Property Property --> Contract end subgraph BestPractice ["5. 最佳实践"] ObjectsUtil["使用 Objects.equals() / hash()"] AutoTool["IDE 自动生成 / Lombok (@Data)"] SafeCheck["'常量'.equals(变量) 规避 NPE"] end %% 逻辑连接 Root ==> Hierarchy Hierarchy ==> Comparison Comparison ==> HashMechanism HashMechanism ==> Rules Rules ==> BestPractice %% 应用样式 class RootNode,Root main; class Compare,Logic decision; class Root term; class ObjectsUtil,AutoTool,SafeCheck storage; ```